﻿// ***********************************************************************
// Assembly         : TSharp.Core
// Author           : tangjingbo
// Created          : 08-16-2013
//
// Last Modified By : tangjingbo
// Last Modified On : 08-19-2013
// ***********************************************************************
// <copyright file="MessageListenerManage.cs" company="Extendsoft">
//     Copyright (c) Extendsoft. All rights reserved.
// </copyright>
// <summary></summary>
// ***********************************************************************
#region

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;

#endregion

namespace TSharp.Core.Message.MessageImpl
{
    /// <summary>
    /// 消息注册管理类
    /// <para>by tangjingbo at 2009/12/14 21:39</para>
    /// </summary>
    internal static class MessageListenerManage
    {
        #region Nested type: Manage

        /// <summary>
        /// Class QueueManage
        /// </summary>
        private class QueueManage
        {
            /// <summary>
            /// The instance
            /// </summary>
            private static readonly QueueManage instance = new QueueManage();

            /// <summary>
            /// The messages
            /// </summary>
            private readonly ConcurrentDictionary<Type, RegisterCollection> Messages =
                new ConcurrentDictionary<Type, RegisterCollection>();

            /// <summary>
            /// Gets the current.
            /// </summary>
            /// <value>The current.</value>
            public static QueueManage Current
            {
                get { return instance; }
            }

            /// <summary>
            /// Gets the collection.
            /// </summary>
            /// <param name="msgType">Type of the MSG.</param>
            /// <returns>RegisterCollection.</returns>
            private RegisterCollection GetCollection(Type msgType)
            {
                // return null;
                return Messages.GetOrAdd(msgType, k => new RegisterCollection());
            }

            /// <summary>
            /// Adds the specified handle.
            /// </summary>
            /// <param name="handle">The handle.</param>
            /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
            public bool Add(IRegisterHandle handle)
            {
                RegisterCollection value = GetCollection(handle.MessageType);
                value.Add(handle);
                return true;
            }

            /// <summary>
            /// Gets the handlers.
            /// </summary>
            /// <typeparam name="TMessage">The type of the T message.</typeparam>
            /// <returns>IEnumerable{IRegisterHandle{``0}}.</returns>
            internal IEnumerable<IRegisterHandle<TMessage>> GetHandlers<TMessage>()
            {
                Type msgType = typeof(TMessage);
                RegisterCollection value = GetCollection(msgType);
                return value.GetAlllHandles(msgType).Cast<IRegisterHandle<TMessage>>();
            }

            /// <summary>
            /// Removes the specified handle.
            /// </summary>
            /// <param name="handle">The handle.</param>
            internal void Remove(IRegisterHandle handle)
            {
                Type msgType = handle.MessageType;
                RegisterCollection value = GetCollection(msgType);

                value.Remove(handle);
            }

            /// <summary>
            /// Removes the specified MSG type.
            /// </summary>
            /// <param name="msgType">Type of the MSG.</param>
            /// <param name="listener">The listener.</param>
            internal void Remove(Type msgType, IHandle listener)
            {
                RegisterCollection value = GetCollection(msgType);

                value.Remove(listener);
            }

            /// <summary>
            /// Class RegisterCollection
            /// </summary>
            private class RegisterCollection
            {
                /// <summary>
                /// The _list
                /// </summary>
                private readonly List<IRegisterHandle> _list = new List<IRegisterHandle>(1000);
                /// <summary>
                /// The _sorted
                /// </summary>
                private bool _sorted = true;

                /// <summary>
                /// Gets the count.
                /// </summary>
                /// <value>The count.</value>
                public int Count
                {
                    get { return _list.Count; }
                }

                /// <summary>
                /// Adds the specified reg handle.
                /// </summary>
                /// <param name="regHandle">The reg handle.</param>
                public void Add(IRegisterHandle regHandle)
                {
                    _list.Add(regHandle);
                    _sorted = _list.Count < 2;
                }

                /// <summary>
                /// Removes the specified reg handle.
                /// </summary>
                /// <param name="regHandle">The reg handle.</param>
                public void Remove(IRegisterHandle regHandle)
                {
                    _list.Remove(regHandle);
                }

                /// <summary>
                /// Removes the specified listener.
                /// </summary>
                /// <param name="listener">The listener.</param>
                internal void Remove(IHandle listener)
                {
                    for (int i = _list.Count - 1; i >= 0; i--)
                    {
                        IRegisterHandle registerHandle = _list[i];
                        if (ReferenceEquals(registerHandle.GetListener(), listener))
                        {
                            _list.RemoveAt(i);
                            break;
                        }
                    }
                }

                /// <summary>
                /// 获取所有实现，并且以优先级自高到低排序
                /// </summary>
                /// <returns>IEnumerable{IRegisterHandle}.</returns>
                internal IEnumerable<IRegisterHandle> GetAlllHandles()
                {
                    if (!_sorted)
                    {
                        _list.Sort();
                        _sorted = true;
                    }
                    return new List<IRegisterHandle>(_list.AsReadOnly());
                }

                /// <summary>
                /// 获取所有实现，并且以优先级自高到低排序
                /// </summary>
                /// <typeparam name="TMessage">The type of the T message.</typeparam>
                /// <returns>IEnumerable{IRegisterHandle}.</returns>
                internal IEnumerable<IRegisterHandle> GetAlllHandles<TMessage>()
                {
                    if (!_sorted)
                    {
                        _list.Sort();
                        _sorted = true;
                    }
                    Type msgType = typeof(TMessage);
                    return GetAlllHandles(msgType);
                }

                /// <summary>
                /// Gets the alll handles.
                /// </summary>
                /// <param name="msgType">Type of the MSG.</param>
                /// <returns>IEnumerable{IRegisterHandle}.</returns>
                internal IEnumerable<IRegisterHandle> GetAlllHandles(Type msgType)
                {
                    if (!_sorted)
                    {
                        _list.Sort();
                        _sorted = true;
                    }
                    return new List<IRegisterHandle>(_list.Where(x => x.MessageType == msgType));
                }
            }
        }

        #endregion

        /// <summary>
        /// The reg handle type
        /// </summary>
        public static readonly Type RegHandleType = typeof(RegisterHandle<>);
        /// <summary>
        /// The handle type
        /// </summary>
        private static readonly Type HandleType = typeof(IHandle);

        /// <summary>
        /// Handles the massage.
        /// </summary>
        /// <typeparam name="TMessage">The type of the T message.</typeparam>
        /// <param name="tran">The tran.</param>
        /// <returns>IMessageResult{``0}.</returns>
        internal static IMessageResult<TMessage> HandleMassage<TMessage>(TransmitterImpl<TMessage> tran)
        {
            lock (QueueManage.Current)
            {
                IEnumerable<IRegisterHandle<TMessage>> handles = QueueManage.Current.GetHandlers<TMessage>();
                if (handles != null)
                {
                    foreach (var handle in handles)
                    {
                        tran.RegHandle = handle;
                        if (tran.IsTerminated)
                            break;

                        if (handle.IsAlive)
                        {
                            IHandle<TMessage> listener = handle.GetListener();
                            if (listener != null)
                            {
                                listener.OnReceive(tran.GetMessage(), tran);
                                tran.GetListeneds++;
                            }
                        }
                    }
                }
                return tran;
            }
        }


        /// <summary>
        /// Removes the handler.
        /// </summary>
        /// <typeparam name="TMessage">The type of the T message.</typeparam>
        /// <param name="handle">The handle.</param>
        public static void RemoveHandler<TMessage>(IRegisterHandle<TMessage> handle)
        {
            lock (QueueManage.Current)
            {
                QueueManage.Current.Remove(handle);
            }
        }

        /// <summary>
        /// Registers the specified listener.
        /// </summary>
        /// <param name="listener">The listener.</param>
        /// <returns>IRegisterHandle[][].</returns>
        internal static IRegisterHandle[] Register(IHandle listener)
        {
            lock (QueueManage.Current)
            {
                Type[] handleTypes =
                    listener.GetType()
                            .GetInterfaces()
                            .Where(x => x != HandleType && HandleType.IsAssignableFrom(x))
                            .ToArray();
                var results = new IRegisterHandle[handleTypes.Length];
                for (int i = 0; i < results.Length; i++)
                {
                    Type handleType = handleTypes[i];
                    Type msgType = handleType.GetGenericArguments()[0];
                    Type implType = RegHandleType.MakeGenericType(msgType);
                    var regHandle = Activator.CreateInstance(implType, listener) as IRegisterHandle;
                    results[i] = regHandle;
                    QueueManage.Current.Add(regHandle);
                }
                return results;
            }
        }

        /// <summary>
        /// Registers the specified listener.
        /// </summary>
        /// <typeparam name="TMessage">The type of the T message.</typeparam>
        /// <param name="listener">The listener.</param>
        /// <param name="order">The order.</param>
        /// <returns>IRegisterHandle{``0}.</returns>
        internal static IRegisterHandle<TMessage> Register<TMessage>(IHandle<TMessage> listener, int order)
        {
            lock (QueueManage.Current)
            {
                var handle = new RegisterHandle<TMessage>(listener) { Order = order };
                QueueManage.Current.Add(handle);
                return handle;
            }
        }

        /// <summary>
        /// Uns the register.
        /// </summary>
        /// <param name="listener">The listener.</param>
        internal static void UnRegister(IHandle listener)
        {
            lock (QueueManage.Current)
            {
                Type[] handleTypes =
                    listener.GetType()
                            .GetInterfaces()
                            .Where(x => x != HandleType && HandleType.IsAssignableFrom(x))
                            .ToArray();
                foreach (Type handleType in handleTypes)
                {
                    Type msgType = handleType.GetGenericArguments()[0];
                    QueueManage.Current.Remove(msgType, listener);
                }
            }
        }
    }
}